不再限制一個工廠(物件)建立許多產品(物件),而是轉變成一個產品(物件)對應一個工廠(物件),而決定生產哪個產品(物件)則轉交給另一個決策者(物件)。
昨天提到,每次新增一個產品時,Simple Factory Method 內負責管理生產的工廠就必須「變動 switch-case
」,此項舉動違反 SOLID 的 OCP。Factory Method 改良這一點,讓每項產品擁有各自的工廠。實際決定要使用哪間工廠的決策者,則轉交給其他物件負責,本身不涉入生產判定。
Factory Method 的作法是:
Class
、Abstract Class
或 Interface
。Interface
。產品親代:PETBottle
public abstract class PETBottle {
protected String smell = "";
protected String color = "";
public PETBottle(String smell, String color) {
this.smell = smell;
this.color = color;
}
public abstract String getTaste();
}
產品子代:Coke
、Water
、OrangeJuice
public class Coke extends PETBottle {
public Coke(String smell, String color) {
super(smell, color);
}
@Override
public String getTaste() {
return "這瓶可樂的顏色:" + color + ",香味是:" + smell;
}
}
public class Water extends PETBottle {
public Water(String smell, String color) {
super(smell, color);
}
@Override
public String getTaste() {
return "這瓶水的顏色:" + color + ",香味是:" + smell;
}
}
public class OrangeJuice extends PETBottle {
public OrangeJuice(String smell, String color) {
super(smell, color);
}
@Override
public String getTaste() {
return "這瓶柳橙汁的顏色:" + color + ",香味是:" + smell;
}
}
工廠親代:PETBottleFactory
public interface PETBottleFactory {
public PETBottle getPET_Bottle();
}
工廠子代:CokeFactory
、WaterFactory
、OrangeJuiceFactory
public class CokeFactory implements PETBottleFactory {
@Override
public PETBottle getPET_Bottle() {
System.out.println("機器選定可樂瓶子");
System.out.println("黑色液體衝入瓶子內");
System.out.println("轉上瓶蓋,完成");
return new Coke("甜甜的", "黑色");
}
}
public class OrangeJuiceFactory implements PETBottleFactory {
@Override
public PETBottle getPET_Bottle() {
System.out.println("機器選定礦泉柳橙汁瓶子");
System.out.println("橘色液體衝入瓶子內");
System.out.println("轉上瓶蓋,完成");
return new OrangeJuice("酸酸的", "橘色");
}
}
public class WaterFactory implements PETBottleFactory {
@Override
public PETBottle getPET_Bottle() {
System.out.println("機器選定礦泉水瓶子");
System.out.println("透明液體衝入瓶子內");
System.out.println("轉上瓶蓋,完成");
return new Water("無味", "透明的");
}
}
決策者:
public class PETBottleFactoryMethodSample {
public static void main(String[] args) {
System.out.println("今天我想來點,可樂!");
PETBottleFactory cokeFactory = new CokeFactory();
PETBottle coke = cokeFactory.getPET_Bottle();
System.out.println("得到一瓶可樂!");
System.out.println(coke.getTaste());
System.out.println("---咳咳咳---");
System.out.println("有點甜,我想喝點,礦泉水!");
PETBottleFactory waterFactory = new WaterFactory();
PETBottle water = waterFactory.getPET_Bottle();
System.out.println("得到一瓶礦泉水!");
System.out.println(water.getTaste());
System.out.println("---咕嚕咕嚕---");
System.out.println("清爽!最來來點,柳橙汁!");
PETBottleFactory orangeJuiceFactory = new OrangeJuiceFactory();
PETBottle orangeJuice = orangeJuiceFactory.getPET_Bottle();
System.out.println("得到一瓶柳橙汁!");
System.out.println(orangeJuice.getTaste());
}
}
受限於 JavaScript 沒有虛擬型別、無法限制型別。
產品親代:PETBottle
/** @abstract */
class PETBottle {
constructor(smell, color) {
this.smell = smell;
this.color = color;
}
getTaste() { return; }
}
產品子代:Coke
、Water
、OrangeJuice
class Coke extends PETBottle {
constructor(smell, color) {
super(smell, color);
}
/** @override */
getTaste() {
return "這瓶可樂的顏色:" + this.color + ",香味是:" + this.smell;
}
}
class Water extends PETBottle {
constructor(smell, color) {
super(smell, color);
}
/** @override */
getTaste() {
return "這瓶水的顏色:" + this.color + ",香味是:" + this.smell;
}
}
class OrangeJuice extends PETBottle {
constructor(smell, color) {
super(smell, color);
}
/** @override */
getTaste() {
return "這瓶柳橙汁的顏色:" + this.color + ",香味是:" + this.smell;
}
}
工廠親代:PETBottleFactory
/** @interface */
class PETBottleFactory {
getPET_Bottle() { return; }
}
工廠子代:CokeFactory
、WaterFactory
、OrangeJuiceFactory
class CokeFactory extends PETBottleFactory {
/** @override */
getPET_Bottle() {
console.log("機器選定可樂瓶子");
console.log("黑色液體衝入瓶子內");
console.log("轉上瓶蓋,完成");
return new Coke("甜甜的", "黑色");
}
}
class WaterFactory extends PETBottleFactory {
/** @override */
getPET_Bottle() {
console.log("機器選定礦泉水瓶子");
console.log("透明液體衝入瓶子內");
console.log("轉上瓶蓋,完成");
return new Coke("甜甜的", "黑色");
}
}
class OrangeJuiceFactory extends PETBottleFactory {
/** @override */
getPET_Bottle() {
console.log("機器選定礦泉柳橙汁瓶子");
console.log("橘色液體衝入瓶子內");
console.log("轉上瓶蓋,完成");
return new OrangeJuice("酸酸的", "橘色");
}
}
決策者:
const PETBottleFactoryMethodSample = () => {
console.log("今天我想來點,可樂!");
const cokeFactory = new CokeFactory();
const coke = cokeFactory.getPET_Bottle();
console.log("得到一瓶可樂!");
console.log(coke.getTaste());
console.log("---咳咳咳---");
console.log("有點甜,我想喝點,礦泉水!");
const waterFactory = new WaterFactory();
const water = waterFactory.getPET_Bottle();
console.log("得到一瓶礦泉水!");
console.log(water.getTaste());
console.log("---咕嚕咕嚕---");
console.log("清爽!最來來點,柳橙汁!");
const orangeJuiceFactory = new OrangeJuiceFactory();
const orangeJuice = orangeJuiceFactory.getPET_Bottle();
console.log("得到一瓶柳橙汁!");
console.log(orangeJuice.getTaste());
};
PETBottleFactoryMethodSample();
Factory Method 改善了 Simple Factory Method 無法遵守 SOLID 的問題,將「選擇」交給決策者,本身不涉及選擇,只負責生產。
然而,這個生產是直線關係,工廠對應產品,假如生產的產品數量增加非常多時,整體程式會顯得笨重、重複。此時,如果能找出產品之間的共通點,那就能抽離出來,重構後變成新的 Factory 模式。
明天,將介紹 Abstract Factory 模式。